﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Core.h".
//-------------------------------------------------------------------

#ifndef _UXS_COPY_STRATEGY_TYPE_H
#define _UXS_COPY_STRATEGY_TYPE_H

#pragma once

#include "../Types/MemFunc.h"
#include "../Types/Utils.h"

namespace UX_STL
{
namespace UXTypes
{
	
	struct MemMover;
	
/*
=================================================
	меняет местами
=================================================
*/
	template <typename T>
	struct TSwap
	{
		inline void operator () (INOUT T &a, INOUT T &b) const
		{
			T c(a);
			a = b;
			b = c;
		}

		inline void operator () (INOUT T &a, INOUT T &b, INOUT T &c) const
		{
			c = a;
			a = b;
			b = c;
		}
		
		inline void Set (OUT T &to, const T &from) const
		{
			to = from;
		}

		inline void Clear (OUT T &a) const
		{
			a = T();
		}
	};

	template <typename T>
	inline void _swap (INOUT T &a, INOUT T &b)
	{
		TSwap<T>() ( a, b );
	}


	template <typename T>
	inline void _swap (INOUT T &a, INOUT T &b, INOUT T &c)
	{
		TSwap<T>() ( a, b, c );
	}

/*
=================================================
	меняет местами без вызова конструктора
	и деструктора
=================================================
*/
	template <typename T>
	struct TSwapMC
	{
		inline void operator () (INOUT T &a, INOUT T &b) const
		{
			uint8	buf[ sizeof(T) ];
			MemCopy( buf, &a, sizeof(T) );
			MemCopy( &a,  &b, sizeof(T) );
			MemCopy( &b, buf, sizeof(T) );
		}

		inline void operator () (INOUT T &a, INOUT T &b, INOUT T &buf) const
		{
			MemCopy( &buf, &a, sizeof(T) );
			MemCopy( &a,   &b, sizeof(T) );
			MemCopy( &b, &buf, sizeof(T) );
			//MemSet( &buf, 0,  sizeof(T) );
		}

		inline void Set (OUT T &to, const T &from) const
		{
			MemCopy( &to, &from, sizeof(T) );
		}

		inline void Clear (OUT T &a) const
		{
			MemSet( &a, 0, sizeof(a) );
		}
	};

/*
	template <typename T>
	inline void _swapc(T &a, T &b)
	{
		TSwapMC<T>() ( a, b );
	}
	

	template <typename T>
	inline void _swapc(T &a, T &b, T &buf)
	{
		TSwapMC<T>() ( a, b, buf );
	}
	
/*
=================================================
	меняет местами целочисленные типы и указатели
=================================================
*
	template <typename T>
	inline void _swapI(T &a, T &b)
	{
		a ^= (b ^= (a ^= b));
	}

	template <typename T>
	inline void _swapI(T *a, T *b)
	{
		return _swapI( reinterpret_cast< usize &>(a), reinterpret_cast< usize &>(b) );
	}
*/




	
	//
	// Default Copy Strategy
	//

	template <typename T>
	struct TCopyStrategy
	{
		typedef TSwapMC<T>	swap_t;

		static void Construct (T *ptr, const T& e)
		{
			new ((void*)ptr) T(e);
		}

		static void Construct (T *ptr, T& e)
		{
			new ((void*)ptr) T(e);
		}

		RVALUE_REFERENCE_ONLY(
			static void Construct (T *ptr, T&& e)
			{
				new ((void*)ptr) T( ToRValueRef(e) );
			}
		)

		static void Destruct (T *ptr)
		{
			ptr->~T();
		}

		static void Create (T *ptr, usize count)
		{
			for (usize i = 0; i < count; ++i)
				new ((void*)(ptr + i)) T();
		}

		static void Destroy (T *ptr, usize count)
		{
			for (usize i = 0; i < count; ++i)
				Destruct( ptr + i );
		}

		static void Copy (T *to, const T * const from, const usize count)
		{
			for (usize i = 0; i < count; ++i)
				Construct( to+i, from[i] );
		}

		static void Copy (T *to, T *from, const usize count)
		{
			for (usize i = 0; i < count; ++i)
				Construct( to+i, from[i] );
		}

		static void Replace (T *to, T *from, const usize count)
		{
			MemMove( to, from, sizeof(T)*count );
		}

		static void Replace (T *ptr, T& e)				// Construct & Destruct
		{
			MemCopy( ptr, &e, sizeof(T) );
		}

		static void ZeroMem (T *ptr, usize count)
		{
			UXTypes::ZeroMem( ptr, sizeof(T)*count );
		}
	};



	//
	// Safe Copy Strategy
	//

	template <typename T>
	struct TSafeCopyStrategy
	{
		typedef TSwap<T>	swap_t;

		static void Construct (T *ptr, const T& e)
		{
			new ((void*)ptr) T(e);
		}

		static void Construct (T *ptr, T& e)
		{
			new ((void*)ptr) T(e);
		}
		
		RVALUE_REFERENCE_ONLY(
			static void Construct (T *ptr, T&& e)
			{
				new ((void*)ptr) T( ToRValueRef(e) );
			}
		)

		static void Destruct (T *ptr)
		{
			ptr->~T();
		}

		static void Create (T *ptr, usize count)
		{
			for (usize i = 0; i < count; ++i)
				new ((void*)(ptr + i)) T();
		}

		static void Destroy (T *ptr, usize count)
		{
			for (usize i = 0; i < count; ++i)
				Destruct( ptr + i );
		}

		static void Copy (T *to, const T * const from, const usize count)
		{
			for (usize i = 0; i < count; ++i)
				Construct( to+i, from[i] );
		}

		static void Copy (T *to, T *from, const usize count)
		{
			for (usize i = 0; i < count; ++i)
				Construct( to+i, from[i] );
		}

		static void Replace (T *to, T *from, const usize count)
		{
			for (usize i = 0; i < count; ++i)
				Replace( to+i, from[i] );
		}

		static void Move (T *to, T *from, const usize count)
		{
			for (usize i = 0; i < count; ++i)
				Replace( to+i, ToRValueRef( from[i] ) );		// TODO: check
		}

		static void Replace (T *ptr, T& e)			// Construct & Destruct
		{
			new ((void*)ptr) T(e);
			(&e)->~T();
		}

		RVALUE_REFERENCE_ONLY(
			static void Replace (T *ptr, T&& e)			// Construct & Destruct
			{
				new ((void*)ptr) T( ToRValueRef(e) );
			}
		)

		static void ZeroMem (T *ptr, usize count)
		{
			UXTypes::ZeroMem( ptr, sizeof(T)*count );
		}
	};



	//
	// Safe Optimized Copy Strategy
	//

	template <typename T>
	struct TSafeOptCopyStrategy
	{
		typedef TSwap<T>	swap_t;

		static void Construct (T *ptr, const T& e)
		{
			new ((void*)ptr) T(e);
		}

		static void Construct (T *ptr, T& e)
		{
			new ((void*)ptr) T(e);
		}
		
		RVALUE_REFERENCE_ONLY(
			static void Construct (T *ptr, T&& e)
			{
				new ((void*)ptr) T( ToRValueRef(e) );
			}
		)

		static void Destruct (T *ptr)
		{
			ptr->~T();
		}

		static void Create (T *ptr, usize count)
		{
			for (usize i = 0; i < count; ++i)
				new ((void*)(ptr + i)) T();
		}

		static void Destroy (T *ptr, usize count)
		{
			for (usize i = 0; i < count; ++i)
				Destruct( ptr + i );
		}

		static void Copy (T *to, const T * const from, const usize count)
		{
			for (usize i = 0; i < count; ++i)
				Construct( to+i, from[i] );
		}

		static void Copy (T *to, T *from, const usize count)
		{
			for (usize i = 0; i < count; ++i)
				Construct( to+i, from[i] );
		}

#	if not UX_RVALUE_REFERENCE_SUPPORTED
		static void Replace (T *to, T *from, const usize count)
		{
			for (usize i = 0; i < count; ++i)
				Replace( to+i, from[i] );
		}
#	else
		static void Replace (T *to, T *from, const usize count)
		{
			for (usize i = 0; i < count; ++i)
				Replace( to+i, ToRValueRef( from[i] ) );		// TODO: check
		}
#	endif

		static void Replace (T *ptr, T& e)			// Construct & Destruct
		{
			new ((void*)ptr) T(e);
			(&e)->~T();
		}

		RVALUE_REFERENCE_ONLY(
			static void Replace (T *ptr, T&& e)			// Construct & Destruct
			{
				new ((void*)ptr) T( ToRValueRef(e) );
			}
		)

		static void ZeroMem (T *ptr, usize count)
		{
			UXTypes::ZeroMem( ptr, sizeof(T)*count );
		}
	};



	//
	// Fast Copy Strategy
	//

	template <typename T>
	struct TFastCopyStrategy
	{
		typedef TSwapMC<T>	swap_t;

		static void Construct (T *ptr, const T& e)
		{
			*ptr = e;
		}
		static void Construct (T *ptr, T& e)
		{
			*ptr = e;
		}

		static void Create (T *ptr, usize count)
		{
			UXTypes::ZeroMem( ptr, sizeof(T)*count );
		}

		static void Destruct (T *)
		{
		}

		static void Destroy (T *, usize)
		{
		}

		static void Copy (T *to, const T * const from, const usize count)
		{
			MemCopy( to, from, sizeof(T)*count );
		}

		static void Replace (T *to, const T * const from, const usize count)
		{
			MemMove( to, from, sizeof(T)*count );
		}

		static void Replace (T *ptr, T& e)			// Construct & Destruct
		{
			*ptr = e;
		}

		static void ZeroMem (T *ptr, usize count)
		{
			UXTypes::ZeroMem( ptr, sizeof(T)*count );
		}
	};

//-------------------------------------------------------------------

}	// UXTypes
}	// UX_STL

#endif	// _UXS_COPY_STRATEGY_TYPE_H